//
// Created by Administrator on 2020/9/9.
//

#include <cstdlib>
#include <string>
#include <iostream>
#include <memory>
#include <chrono>
#include <thread>
#include <sstream>
#include <functional>
#include "udp_client.h"
#include "stun_header.h"
#include "stun_message.h"
#include "unistd.h"
#include "asio.hpp"
#include "tcp_client.h"
#include "p2p_punch.h"

using namespace std;

//const string stun_server1 = "stun1.l.google.com";
const string stun_server1 = "stun.qq.com";
//const string stun_server1 = "stun.syncthing.com";
const string stun_server11 = "47.97.157.56";
const string stun_server2 = "stun2.l.google.com";
const string stun_server3 = "stun3.l.google.com";
const string stun_server4 = "stun3.l.google.com";
const string stun_server5 = "81.68.245.10";
const string  stun_port = "3478";
const uint16_t  stun_port3 = 3478;
const string record_server = "47.97.157.56";
const string record_port = "8743";

int main(int argc, char* argv[])
{
    P2pPunch punch;
    //udpclient
    asio::io_context io_context_;
    std::shared_ptr<UdpClient> udp_client_;
    while (true) {
        try {
            uint16_t local_port = UdpClient::get_random(UdpClient::UDP_PORT_MIN, UdpClient::UDP_PORT_MAX);
            udp_client_ = std::make_shared<UdpClient>(local_port, io_context_, punch.peer_mgr());
            std::cout << "use local port: " << local_port << std::endl;
            break;
        } catch (std::system_error &e) {
            cout << e.what() << endl;
        }
    }

    //tcp_client
    asio::io_context io_context2;
    std::string server_ip = "47.97.157.56";
    std::string server_port = "8743";

    tcp::resolver resolver(io_context2);
    auto endpoints = resolver.resolve(server_ip, server_port);
    tcp_client client(io_context2, endpoints, *udp_client_);
    std::thread tcp_thread([&io_context2](){ io_context2.run(); });

    punch.add_client(udp_client_);
    punch.notify_self_info(client);

    std::thread udp_thread([&io_context_](){ io_context_.run(); });

    udp_client_->do_receive();

    while(1){
        std::vector<std::string> peer_info = client.get_peer();

        punch.add_peers(client.get_peer());
        punch.dump_peer_mgr();

        punch.punch();

        punch.notify_self_result(client);

        //punch.refresh_peers();
        
        this_thread::sleep_for(std::chrono::seconds(1));
    }

    tcp_thread.join();
    udp_thread.join();

    return 0;
}

